package com.example.martian.utils;

import com.alibaba.fastjson.JSONObject;
import okhttp3.*;
import okio.ByteString;
import org.bitcoinj.core.ECKey;
import org.bitcoinj.core.Sha256Hash;
import org.springframework.stereotype.Component;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.TreeMap;

@Component
public class Custody {

    private static String API_KEY = "03001358d417f9237c7f6519c61438f5b9fb29978a6218cb93120914e73184e2a4";
    private static String API_SECRET = "cb2513b1b7c4a0e5deac1901d03eb6a36bdaa2a4007c75854f3f58d9e27d499a";
    private static String HOST = "https://api.sandbox.cobo.com";
    private static String COBO_PUB = "032f45930f652d72e0c90f71869dfe9af7d713b1f67dc2f7cb51f9572778b9c876";
    private static OkHttpClient HTTP_CLIENT = new OkHttpClient();

    private static String bytes2Hex(byte[] b) {
        return ByteString.of(b).hex();
    }


    public static void testGenerateKeysAndSignMessage() {
        ECKey key = new ECKey();
        String privHex = bytes2Hex(key.getPrivKeyBytes());
        String pubHex = bytes2Hex(key.getPubKey());
        System.out.println("API_KEY: " + pubHex + "; API_SECRET: " + privHex);
    }

//    public static void main(String... args) throws Exception {
//        if (args.length == 1 && args[0].equals("key")){
//            testGenerateKeysAndSignMessage();
//        } else {
//            testApi();
//        }
//    }


    public static void testApi() throws Exception {
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("coin", "USDT");
        String res = request("GET", "/v1/custody/org_info/", params, API_KEY,
                API_SECRET, HOST);
        System.out.println(res);
    }

    private static String request(String method, String path, TreeMap<String, Object> params, String apiKey, String apiSecret, String host) throws Exception {
        method = method.toUpperCase();
        String nonce = String.valueOf(System.currentTimeMillis());

        String paramString = composeParams(params);

        String content = method + "|" + path + "|" + nonce + "|" + paramString;

        String signature = generateEccSignature(content, apiSecret);

        Request.Builder builder = new Request.Builder()
                .addHeader("Biz-Api-Key", apiKey)
                .addHeader("Biz-Api-Nonce", nonce)
                .addHeader("Biz-Api-Signature", signature);
        Request request;
        if ("GET".equalsIgnoreCase(method)) {
            request = builder
                    .url(host + path + "?" + paramString)
                    .build();
        } else if ("POST".equalsIgnoreCase(method)) {
            FormBody.Builder bodyBuilder = new FormBody.Builder();
            params.forEach((s, o) -> bodyBuilder.add(s, String.valueOf(o)));
            RequestBody formBody = bodyBuilder.build();
            request = builder
                    .url(host + path)
                    .post(formBody)
                    .build();
        } else {
            throw new RuntimeException("not supported http method");
        }
        try (Response response = HTTP_CLIENT.newCall(request).execute()) {
            String ts = response.header("BIZ_TIMESTAMP");
            String sig = response.header("BIZ_RESP_SIGNATURE");
            String body = response.body().string();
            boolean verifyResult = verifyResponse(body + "|" + ts, sig, COBO_PUB);
            System.out.println("verify success? " + verifyResult);
            if (!verifyResult) {
                throw new RuntimeException("verify response error");
            }
            return body;
        }
    }
    private static String composeParams(TreeMap<String, Object> params) {
        StringBuffer sb = new StringBuffer();
        params.forEach((s, o) -> {
            try {
                sb.append(s).append("=").append(URLEncoder.encode(String.valueOf(o), "UTF-8")).append("&");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        });
        if (sb.length() > 0) {
            sb.deleteCharAt(sb.length() - 1);
        }
        return sb.toString();
    }

    private static String generateEccSignature(String content, String key) {
        ECKey eckey = ECKey.fromPrivate(hexStringToBytes(key));
        byte[] bytes = eckey.sign(Sha256Hash.wrap(doubleSha256(content))).encodeToDER();
        return bytes2Hex(bytes);
    }

    private static byte[] hex2bytes(String s) {
        return ByteString.decodeHex(s).toByteArray();
    }

    private static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }


    private static byte[] doubleSha256(String content) {
        return Sha256Hash.hashTwice(content.getBytes());
    }

    private static boolean verifyResponse(String content, String sig, String pubkey) throws Exception {
        ECKey key = ECKey.fromPublicOnly(hex2bytes(pubkey));
        return key.verify(doubleSha256(content), hex2bytes(sig));
    }

    //获取充值地址
    public static JSONObject getCoinAddress(String coin) throws Exception {
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("coin",coin);
        String res = request("POST", "/v1/custody/new_address/", params, API_KEY,
                API_SECRET, HOST);
        JSONObject jsonObject = JSONObject.parseObject(res);
        return jsonObject;
    }

    //获取测试充值地址
    public static JSONObject getTestCoinAddress() throws Exception {
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("coin","TETH");
        String res = request("POST", "/v1/custody/new_address/", params, API_KEY,
                API_SECRET, HOST);
        JSONObject jsonObject = JSONObject.parseObject(res);
        System.out.println(jsonObject);
        return jsonObject;
    }

    //验证地址合法性
    public static Boolean address_info(String coin,String addressKey) throws Exception {
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("coin",coin);
        params.put("address",addressKey);
        String res = request("GET", "/v1/custody/address_info/", params, API_KEY,
                API_SECRET, HOST);
        JSONObject jsonObject = JSONObject.parseObject(res);
        String success = jsonObject.get("success").toString();
        if (success.equals("true")){
            System.out.println(success.equals("true"));
            return true;
        }
        System.out.println(success.equals("true"));
        return false;
    }

    //查询地址到账信息
    public static JSONObject transaction_history(String min_id) throws Exception {
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("side","deposit");
        params.put("min_id",min_id);
        String res = request("GET", "/v1/custody/transaction_history/", params, API_KEY,
                API_SECRET, HOST);
        JSONObject jsonObject = JSONObject.parseObject(res);
        return jsonObject;
    }

    public static void main(String[] args) throws Exception {
        testGenerateKeysAndSignMessage();
        test();
    }

    public static String test(){
//        10^12 * 86400 * 6.25 / (2^32 * 21865558044610.51)  = ;
        double pow = Math.pow(2, 32);
        System.out.println(pow);
        BigDecimal bigDecimal = new BigDecimal(1e12 * 86400 * 6.25);
        System.out.println(bigDecimal);
        BigDecimal decimal = new BigDecimal(pow * 21865558044610.51);
        System.out.println(decimal);

        String scale = bigDecimal.divide(decimal,10,BigDecimal.ROUND_HALF_UP).toPlainString();
        System.out.println(scale);
        return scale;
    }
    //查询账户详情
    public static JSONObject checkWellatMine() throws Exception {
        TreeMap<String, Object> params = new TreeMap<>();
        String res = request("get", "/v1/custody/org_info/", params, API_KEY,
                API_SECRET, HOST);
        JSONObject jsonObject = JSONObject.parseObject(res);
        return jsonObject;
    }

    //提现
    public static JSONObject getCoinWithdraw(String coin,String toAddress,String value,String uuid) throws Exception {
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("coin",coin);
        params.put("address",toAddress);
        params.put("request_id",uuid);
        params.put("amount",value);
        String res = request("POST", "/v1/custody/new_withdraw_request/", params, API_KEY,
                API_SECRET, HOST);
        JSONObject jsonObject = JSONObject.parseObject(res);
        System.out.println(jsonObject);
        return jsonObject;
    }

    //获取提现信息
    public static JSONObject withdraw_info_by_request_id(String uuid) throws Exception {
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("request_id",uuid);
        String res = request("GET", "/v1/custody/withdraw_info_by_request_id/", params, API_KEY,
                API_SECRET, HOST);
        System.out.println(res+"1!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        JSONObject jsonObject = JSONObject.parseObject(res);
        return jsonObject;
    }

    public static JSONObject getCoinsymbol() throws Exception {
        TreeMap<String, Object> params = new TreeMap<>();
        params.put("pay_coin","BTC");
        params.put("get_coin","LTC");
        params.put("pay_coin_decima",24);
        params.put("get_coin_decimal",24);
        String res = request("get", "/v1/custody/otc_coin_pairs/", params, API_KEY,
                API_SECRET, HOST);
        JSONObject jsonObject = JSONObject.parseObject(res);
        return jsonObject;
    }

}
